import 'dart:async';
import 'dart:io';
import 'dart:math';

// Demonstrates variable declaration and usage in Dart.
void variablesDemo() {
  print('\n');
  print('=' * 50); // Changed separator for visual distinction.
  print('Variable Demonstration');
  print('=' * 50);

  // Declaring variables with different types.
  var probeName = 'Explorer II'; // Changed variable name.
  var launchYear = 1980; // Changed year for uniqueness.
  var dishSize = 4.2; // Changed antenna diameter.
  var visitedPlanets = ['Mars', 'Venus', 'Jupiter', 'Saturn']; // Modified list.
  var probeImage = {
    'labels': ['jupiter'], // Changed key name.
    'path': '//images/probe.jpg', // Changed URL.
  };

  // String interpolation to display variable values.
  print(
    'Probe: $probeName, Launched: $launchYear, Dish Size: $dishSize m, Visited: $visitedPlanets, Image: $probeImage',
  );
}

// Demonstrates control flow statements like if, for, and while.
void controlFlowDemo() {
  print('\n');
  print('=' * 50);
  print('Control Flow Demonstration');
  print('=' * 50);

  // Get the current year for comparison.
  var currentYear = DateTime.now().year;

  // Conditional statement to check the century.
  if (currentYear >= 2001) {
    print('In the 21st century');
  } else if (currentYear >= 1901) {
    print('In the 20th century');
  }

  // List of celestial objects for iteration.
  var celestialObjects = ['Moon', 'Sun', 'Star']; // Changed list items.
  // For-in loop to iterate over the list.
  for (final obj in celestialObjects) {
    print('Object: $obj');
  }

  // For loop to print months of the year.
  for (int month = 1; month <= 12; month++) {
    print('Month: $month');
  }

  // While loop to increment year until a condition is met.
  var year = 2010; // Changed starting year.
  while (year < 2017) {
    year += 1;
    print('Year: $year');
  }
}

// Calculates the nth Fibonacci number recursively.
int calculateFibonacci(int n) {
  // Base cases for Fibonacci sequence.
  if (n == 0 || n == 1) return n;
  return calculateFibonacci(n - 1) + calculateFibonacci(n - 2);
}

// Checks if a string contains a specific substring.
bool containsText(String text, String target) {
  return text.contains(target);
}

// Demonstrates function usage, including anonymous functions and higher-order functions.
void functionsDemo() {
  print('\n');
  print('=' * 50);
  print('Function Demonstration');
  print('=' * 50);

  // Calculate Fibonacci number for n=8 (changed from 9).
  var fibResult = calculateFibonacci(8);
  print('Fibonacci(8) = $fibResult');

  // List of phrases for filtering.
  var phrases = [
    'greetings',
    'xyz',
    '456',
    'how are you',
    'pleased to meet you', // Changed list items.
  ];

  // Filter phrases containing 'you' using an anonymous function.
  phrases.where((phrase) => phrase.contains('you')).forEach(print);

  // Filter phrases containing 'o' using a named function.
  var matches = phrases.where((x) => containsText(x, 'o'));
  for (var match in matches) {
    print('Match found: $match');
  }
}

// Demonstrates different types of comments in Dart.
void commentsDemo() {
  print('\n');
  print('=' * 50);
  print('Comments Demonstration');
  print('=' * 50);

  /// This is a documentation comment.
  /// Used to document libraries, classes, or members for tools like IDEs or dartdoc.

  /* This is a block comment, useful for longer explanations or temporary code disabling. */
  print('This section shows comment usage.');
}

// Demonstrates importing and using Dart's math library.
void importsDemo() {
  print('\n');
  print('=' * 50);
  print('Imports Demonstration');
  print('=' * 50);

  // Using the pi constant from dart:math.
  var piValue = pi;
  print('Value of pi: $piValue');

  // Calculate sine of pi/6 (changed from pi/4).
  var angle = pi / 6;
  var sineValue = sin(angle);
  print('sin(pi/6) = $sineValue');
}

// Defines a Spacecraft class to demonstrate object-oriented programming.
class Spacecraft {
  String name;
  DateTime? launchDate;

  // Getter for the launch year.
  int? get launchYear => launchDate?.year;

  // Constructor with syntactic sugar for member initialization.
  Spacecraft(this.name, this.launchDate) {
    // Initialization code could be added here.
  }

  // Named constructor for unlaunched spacecraft.
  Spacecraft.unlaunched(String name) : this(name, null);

  // Method to describe the spacecraft.
  void describe() {
    print('Spacecraft Name: $name');
    if (launchDate != null) {
      int years = DateTime.now().difference(launchDate!).inDays ~/ 365;
      print('Launched in: $launchYear ($years years ago)');
    } else {
      print('Not yet launched');
    }
  }
}

// Demonstrates class creation and usage.
void classesDemo() {
  print('\n');
  print('=' * 50);
  print('Classes Demonstration');
  print('=' * 50);

  // Create instances of Spacecraft.
  var explorer = Spacecraft(
    'Explorer I',
    DateTime(1980, 10, 10),
  ); // Changed name and date.
  var explorer2 = Spacecraft.unlaunched('Explorer II');

  explorer.describe();
  explorer2.describe();
}

// Demonstrates inheritance by extending the Spacecraft class.
class Orbiter extends Spacecraft {
  double altitude;

  Orbiter(super.name, DateTime super.launchDate, this.altitude);

  // Override the describe method to include altitude.
  @override
  void describe() {
    super.describe();
    print('Orbiting at: $altitude km');
  }
}

void inheritanceDemo() {
  print('\n');
  print('=' * 50);
  print('Inheritance Demonstration');
  print('=' * 50);

  // Create an Orbiter instance.
  var orbiter = Orbiter(
    'SkyLab',
    DateTime(2020, 5, 15),
    400.5,
  ); // Changed name and date.
  orbiter.describe();
}

// Mixin to add crew-related functionality.
mixin Piloted {
  int astronauts = 2; // Changed default number.

  // Method to describe the crew.
  void describeCrew() {
    print('Crew size: $astronauts astronauts');
  }
}

// Combines Spacecraft with Piloted mixin.
class PilotedCraft extends Spacecraft with Piloted {
  PilotedCraft(super.name, DateTime super.launchDate);
}

void mixinsDemo() {
  print('\n');
  print('=' * 50);
  print('Mixins Demonstration');
  print('=' * 50);

  // Create a PilotedCraft instance.
  var crewedCraft = PilotedCraft(
    'Apollo',
    DateTime(2000, 7, 20),
  ); // Changed name and date.
  crewedCraft.describe();
  crewedCraft.describeCrew();
}

// Implements the Spacecraft interface to demonstrate interfaces.
class MockSpaceship implements Spacecraft {
  @override
  DateTime? launchDate;

  @override
  String name;

  MockSpaceship(this.name, this.launchDate);

  @override
  void describe() {
    print('Mock Spacecraft: $name');
  }

  @override
  int? get launchYear => launchDate?.year;
}

void interfacesDemo() {
  print('\n');
  print('=' * 50);
  print('Interfaces and Abstract Classes Demonstration');
  print('=' * 50);

  // Create a mock spacecraft.
  var mockCraft = MockSpaceship('Prototype', null); // Changed name.
  mockCraft.describe();
}

// Demonstrates asynchronous programming with async/await.
Future<void> asyncDemo() async {
  print('\n');
  print('=' * 50);
  print('Async Demonstration');
  print('=' * 50);

  const delay = Duration(seconds: 1);

  // Async function with await for delayed printing.
  Future<void> delayedPrint(String message) async {
    await Future.delayed(delay);
    print(message);
  }

  delayedPrint('Delayed message 1');
  print('Completed 1.');

  // Alternative async approach using then.
  Future<void> delayedPrint2(String message) {
    return Future.delayed(delay).then((_) => print(message));
  }

  delayedPrint2('Delayed message 2');
  print('Completed 2.');

  // Async function to create description files.
  Future<void> generateFiles(Iterable<String> items) async {
    for (final item in items) {
      try {
        var file = File('$item.txt');
        if (await file.exists()) {
          var lastModified = await file.lastModified();
          print('File for $item exists, last modified: $lastModified.');
          continue;
        }
        await file.create();
        await file.writeAsString('Description of $item starts here.');
        print('Created file for $item.');
      } on IOException catch (e) {
        print('Error creating file for $item: $e');
      }
    }
  }

  var items = ['Drone', 'Satellite', 'Rover']; // Changed list items.
  generateFiles(items);

  await Future.delayed(Duration(seconds: 5));
}

// Demonstrates Stream usage for asynchronous data handling.
Future<void> streamDemo() async {
  print('\n');
  print('=' * 50);
  print('Stream Demonstration');
  print('=' * 50);

  const delay = Duration(seconds: 1);

  // Create a StreamController to manage stream events.
  StreamController<double> controller = StreamController<double>();
  Stream stream = controller.stream;

  // Listen to stream events.
  stream.listen((event) {
    print('Stream event: $event');
  });

  // Add events to the stream with a delay.
  Future<void> addDelayedEvent(double value) async {
    await Future.delayed(delay);
    controller.add(value);
  }

  addDelayedEvent(10.5); // Changed values.
  addDelayedEvent(20.5);
  addDelayedEvent(30.5);

  await Future.delayed(Duration(seconds: 5));
}

// Demonstrates exception handling with async file operations.
// Demonstrates exception handling with async file operations.
Future<void> readDescriptions(List<String> items) async {
  // Changed Iterable to List
  try {
    for (final item in items) {
      var content = await File('$item.txt').readAsString();
      print('Content of $item.txt: $content');
    }
  } on IOException catch (ex) {
    print('Error reading file: $ex');
  } finally {
    items.clear(); // Clear the list after processing (now valid for List).
  }
}

void exceptionsDemo() {
  print('\n');
  print('=' * 50);
  print('Exceptions Demonstration');
  print('=' * 50);

  var items = [
    'Drone',
    'Satellite',
    'Rover',
    'Tablet',
  ]; // Already a List<String>
  readDescriptions(items);
}

Future<void> main(List<String> args) async {
  // Run each demonstration in sequence.
  variablesDemo();
  controlFlowDemo();
  functionsDemo();
  commentsDemo();
  importsDemo();
  classesDemo();
  inheritanceDemo();
  mixinsDemo();
  interfacesDemo();
  await asyncDemo();
  await streamDemo();
  exceptionsDemo();
}
